package com.ruoyi.calculator.service.impl;

import com.ruoyi.calculator.service.Calculator;
import org.springframework.stereotype.Component;

import java.util.EmptyStackException;
import java.util.Stack;

@Component
public class CalculatorImpl implements Calculator {

    public Double calculate(String expression) {
        try {
            // 去除空格并验证表达式
            expression = expression.replaceAll("\\s+", "");
            if (expression.isEmpty()) {
                throw new IllegalArgumentException("表达式为空");
            }

            // 使用双栈法（操作数栈和运算符栈）解析表达式
            Stack<Double> numbers = new Stack<>();
            Stack<Character> operators = new Stack<>();

            for (int i = 0; i < expression.length(); i++) {
                char c = expression.charAt(i);

                if (Character.isDigit(c) || c == '.') {
                    // 处理数字
                    StringBuilder numStr = new StringBuilder();
                    while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
                        numStr.append(expression.charAt(i));
                        i++;
                    }
                    i--; // 回退一步
                    numbers.push(Double.parseDouble(numStr.toString()));
                } else if (isOperator(c)) {
                    // 处理运算符
                    while (!operators.isEmpty() && precedence(operators.peek()) >= precedence(c)) {
                        applyOperation(numbers, operators.pop());
                    }
                    operators.push(c);
                } else if (c == '(') {
                    operators.push(c);
                } else if (c == ')') {
                    // 处理括号
                    while (operators.peek() != '(') {
                        applyOperation(numbers, operators.pop());
                    }
                    operators.pop(); // 弹出 '('
                } else {
                    throw new IllegalArgumentException("无效字符: " + c);
                }
            }

            // 处理剩余的运算符
            while (!operators.isEmpty()) {
                applyOperation(numbers, operators.pop());
            }

            if (numbers.size() != 1 || !operators.isEmpty()) {
                throw new IllegalArgumentException("无效表达式");
            }

            return numbers.pop();
        } catch (EmptyStackException e) {
            throw new IllegalArgumentException("表达式错误：括号或运算符不匹配");
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("数字格式无效");
        } catch (ArithmeticException e) {
            throw new ArithmeticException("数学错误: " + e.getMessage());
        }
    }

    private boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
    }

    private int precedence(char op) {
        switch (op) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
                return 2;
            case '^':
                return 3;
            default:
                return 0;
        }
    }

    private void applyOperation(Stack<Double> numbers, char op) {
        double b = numbers.pop();
        double a = numbers.pop();
        switch (op) {
            case '+':
                numbers.push(a + b);
                break;
            case '-':
                numbers.push(a - b);
                break;
            case '*':
                numbers.push(a * b);
                break;
            case '/':
                if (b == 0) {
                    throw new ArithmeticException("除零错误");
                }
                numbers.push(a / b);
                break;
            case '^':
                numbers.push(Math.pow(a, b));
                break;
            default:
                throw new IllegalArgumentException("未知运算符: " + op);
        }
    }

    // 扩展功能：科学计算器
    public Double calculateExtended(String expression) {
        try {
            expression = expression.replaceAll("\\s+", "").toLowerCase();
            if (expression.isEmpty()) {
                throw new IllegalArgumentException("表达式为空");
            }

            // 处理函数调用（如 sqrt(4)）
            if (expression.contains("(") && expression.contains(")")) {
                int leftBracket = expression.indexOf('(');
                int rightBracket = expression.indexOf(')');
                if (leftBracket > rightBracket) {
                    throw new IllegalArgumentException("括号不匹配");
                }

                String funcName = expression.substring(0, leftBracket);
                String argStr = expression.substring(leftBracket + 1, rightBracket);
                double arg = Double.parseDouble(argStr);

                switch (funcName) {
                    case "sqrt":   //平方根
                        return Math.sqrt(arg);
                    case "square":  //平方
                        return arg * arg;
                    case "cube":    //立方
                        return arg * arg * arg;
                    case "cbrt":    //立方根
                        return Math.cbrt(arg);
                    case "reciprocal":   //倒数
                        if (arg == 0) {
                            throw new ArithmeticException("除零错误");
                        }
                        return 1 / arg;
                    case "factorial":    // 阶乘
                        if (arg < 0 || arg != (int) arg) {
                            throw new IllegalArgumentException("阶乘参数必须为非负整数");
                        }
                        return factorial((int) arg);
                    case "abs":
                        return Math.abs(arg);
                    case "||":
                        return Math.abs(arg);
                    case "sin":
                        return Math.sin(Math.toRadians(arg));
                    case "cos":
                        return Math.cos(Math.toRadians(arg));
                    case "tan":
                        return Math.tan(Math.toRadians(arg));
                    case "sinh":
                        return Math.sinh(arg);
                    case "cosh":
                        return Math.cosh(arg);
                    case "tanh":
                        return Math.tanh(arg);
                    default:
                        throw new IllegalArgumentException("未知函数: " + funcName);
                }
            } else {
                // 如果不是函数调用，尝试解析为普通表达式
                return calculate(expression);
            }
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("数字格式无效");
        } catch (ArithmeticException e) {
            throw new ArithmeticException("数学错误: " + e.getMessage());
        }
    }

    // 阶乘辅助函数
    private double factorial(int n) {
        if (n == 0 || n == 1) {
            return 1;
        }
        double result = 1;
        for (int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }
}